package org.hive.plugin.videoswf
{
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.utils.Dictionary;
	
	import org.hive.Hive;
	import org.hive.display.LoaderData;
	import org.hive.managers.Manager;
	import org.hive.managers.plugin.LayoutManager;
	import org.hive.managers.plugin.LoadManager;
	import org.hive.sequence.Sequence;
	
	public class VideoSWFManager extends Manager
	{
		public var currentVideo 		: VideoSWF;
		public var isPaused 			: Boolean = false;
		public var isScrubable 			: Boolean = true;
		public var isScrubing 			: Boolean = false;
		public var bufferTolerance 		: Number = 10;
		
		private var __VIDEOS			: Dictionary = new Dictionary( true );
		private var __VIDEOS_BY_NAME	: Dictionary = new Dictionary( true );
		
		public function VideoSWFManager(hive:Hive):void
		{
			super(hive);
		}
		
		public static function init(hive:Hive, layoutManager:LayoutManager, loadManager:LoadManager):VideoSWFManager
		{
			var manager:VideoSWFManager = new VideoSWFManager(hive);
			hive.registerManager(manager);
			
			if(Hive.DEBUG_MODE){trace( "VideoSWFManager :: init" )}
			
			//_____________ Register Object :: Animator
			function videoSWFFunc( action:*, sequence:Sequence, positionInSequence:int ):void {
				if( sequence.getParams( action ) != null){
					layoutManager.addChildAt( action, sequence.getParams( action )[0] );
				} else layoutManager.addChild( action );
				manager.playVideo( action, loadManager.getLoaderByName( manager.getVideoName(action)).name );
			}
			hive.sequenceManager.registerAction(VideoSWF, videoSWFFunc);
			
			
			// Loader Element Distribution
			function loaderElementFunction( loaderElement:* ):void {
				if ( loaderElement.contentLoaderInfo.content as VideoSWF ) {
					manager.add( loaderElement );
				} 	
			}
			loadManager.registerLoaderElement(LoaderData, loaderElementFunction);
			
			return manager;
		}
		
		
		// MANAGEMENT
		public function add( ...args ):void
		{
			for (var i:Number = 0; i < args.length; i++) {
				__VIDEOS_BY_NAME[ args[i].name ] = args[i].contentLoaderInfo.content;
				__VIDEOS[ args[i].contentLoaderInfo.content ] = args[i].name;
		    }
		}
		
		public function remove( video:* ):void
		{
			delete __VIDEOS[ video ];
			delete __VIDEOS_BY_NAME[ video.name ];
		}
		
		public function removeByName( ...names ):void
		{
			for (var i:Number = 0; i < names.length; i++) {
		        remove( getVideoByName( names[i] ) )
		    }
		}
		
		public function getVideoByName( name:String ):VideoSWF
		{
			return __VIDEOS_BY_NAME[ name ];
		}
		
		public function getVideoName( obj:VideoSWF ):String
		{
			return __VIDEOS[ obj ];
		}
		
		
		
		
		
		//CONTROLS
		public function playVideo( video:DisplayObject, name:String ): void
		{
			video.addEventListener( VideoSWFEvent.ON_LABEL, handleLabel, false, 0, true );
			video.addEventListener( Event.ENTER_FRAME, handleEnterFrame, false, 0, true );
			
			if( isBuffering ) stopBuffer();
			
			var previousVideo : VideoSWF = currentVideo as VideoSWF;
			currentVideo = video as VideoSWF;
			currentVideo.gotoAndStop( currentVideo.getLabelByName("vswf_start").frame);
			resume();

			dispatchEvent( new VideoManagerEvent( VideoManagerEvent.ON_VIDEO_SWITCHED, currentVideo, name, previousVideo ) );
		}
		
		public function kill( video:DisplayObject ):void
		{
			var v:VideoSWF = video as VideoSWF;
			v.removeEventListener( VideoSWFEvent.ON_LABEL, handleLabel );
			v.removeEventListener( Event.ENTER_FRAME, handleEnterFrame );
		}
		
		public function pause(): void
		{
			currentVideo.stop();
			dispatchEvent( new VideoManagerEvent( VideoManagerEvent.ON_VIDEO_PAUSED, currentVideo, currentVideo.name, null, currentVideo.currentLabel ) );
			isPaused = true;
		}
		
		public function resume(): void
		{
			var progress:Number = currentVideo.currentFrame/currentVideo.totalFrames;
			currentVideo.play();
			dispatchEvent( new VideoManagerEvent( VideoManagerEvent.ON_VIDEO_RESUMED, currentVideo, currentVideo.name, null, currentVideo.currentLabel, progress ) );
			isPaused = false;
		}
		
		public function scrubVideo( percent:Number ):void
		{
			var position:Number = percent*currentVideo.totalFrames;
			currentVideo.gotoAndStop( Math.round(position) );
		}
		
		public function scrubVideoToLabel( frame:Number ):void
		{
			pause();
			currentVideo.gotoAndStop( frame );
			resume();
		}
		
		private var __videoProgress 		: Number;
		private var __videoSecondsElapsed 	: Number;
		
		public function get videoProgress():Number
		{
			return __videoProgress;
		}
		
		public function frameIsLoaded( frame:Number ):Boolean
		{
			var loaded:Boolean;
			if( frame > currentVideo.framesLoaded ) loaded = false;
			else loaded = true;
			return loaded;
		}
		
		
		
		//Buffering
		private var __bufferToFrame 	: Number;
		private var __isBuffering 	: Boolean = false;
		public function get isBuffering():Boolean { return __isBuffering; }
		
		public function buffer( frame:Number ):void
		{
			__bufferToFrame = frame;
			currentVideo.removeEventListener( Event.ENTER_FRAME, handleEnterFrame );
			currentVideo.addEventListener( Event.ENTER_FRAME, handleBuffering, false, 0, true );
			dispatchEvent( new VideoManagerEvent( VideoManagerEvent.ON_VIDEO_BUFFERING, currentVideo, currentVideo.name ) );
			__isBuffering = true;
			pause();
		}
		
		public function stopBuffer():void
		{
			dispatchEvent( new VideoManagerEvent( VideoManagerEvent.ON_VIDEO_BUFFER_DONE, currentVideo, currentVideo.name ) );
			currentVideo.removeEventListener( Event.ENTER_FRAME, handleBuffering );
			currentVideo.addEventListener( Event.ENTER_FRAME, handleEnterFrame, false, 0, true );
			__isBuffering = false;
			resume();
		}
		
		
		
		
		
		
		//EVENTS
		public function handleEnterFrame( e:Event ):void
		{
			/*
			var fps:Number = e.currentTarget.stage == null ? e.currentTarget.parent.frameRate : e.currentTarget.stage.frameRate;
			
			__videoProgress = (e.currentTarget.currentFrame / e.currentTarget.totalFrames)*100;
			__videoSecondsElapsed = e.currentTarget.currentFrame / 30; //30 = FPS
			e.currentTarget.dispatchEvent( new VideoSWFEvent( VideoSWFEvent.ON_PROGRESS, e.currentTarget.name, "progress", __videoProgress, __videoSecondsElapsed ) );
			*/
			
			dispatchEvent( new VideoManagerEvent( VideoManagerEvent.ON_VIDEO_PROGRESS, e.currentTarget, e.currentTarget.name ) );
			
			if( (e.currentTarget.framesLoaded - e.currentTarget.currentFrame) < bufferTolerance && (e.currentTarget.totalFrames - e.currentTarget.currentFrame) > bufferTolerance && !isScrubing ){
				if( (e.currentTarget.totalFrames - e.currentTarget.currentFrame) < 300 ) buffer( e.currentTarget.totalFrames );
				else buffer( e.currentTarget.currentFrame + 300 );
			}
		}
		
		private function handleBuffering( e:Event ):void
		{
			if( frameIsLoaded( __bufferToFrame ) ){
				stopBuffer();
			}
		}
		
		public function handleLabel( e:VideoSWFEvent ):void
		{
			dispatchEvent( new VideoManagerEvent( VideoManagerEvent.ON_VIDEO_LABEL, currentVideo, e.name, null, e.state ) );
		}
			
	}
}